# app.py - Flask主服务
from flask import Flask, render_template, request, jsonify, redirect, url_for
import serial
import sqlite3
import time
import threading
import cv2
import numpy as np
import face_recognition
from datetime import datetime, timedelta

app = Flask(__name__)

# 串口配置
ser = None
try:
    ser = serial.Serial('COM3', 9600, timeout=1)
except Exception as e:
    print(f"无法连接到Arduino: {e}")

# 数据库配置
def init_db():
    conn = sqlite3.connect('access_control.db')
    cursor = conn.cursor()
    
    # 创建用户表
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        face_encoding BLOB,
        is_admin INTEGER DEFAULT 0,
        created_at TEXT
    )
    ''')
    
    # 创建访问日志表
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS access_logs (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        user_id INTEGER,
        user_name TEXT,
        access_time TEXT,
        result TEXT,
        FOREIGN KEY(user_id) REFERENCES users(id)
    )
    ''')
    
    # 创建访客表
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS visitors (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        phone TEXT,
        valid_until TEXT,
        created_at TEXT
    )
    ''')
    
    conn.commit()
    conn.close()

# 初始化数据库
init_db()

# AI人脸识别模块
class FaceRecognitionSystem:
    def __init__(self):
        self.known_faces = []
        self.known_names = []
        self.known_ids = []
        self.load_known_faces()
        self.camera = None
        
    def load_known_faces(self):
        # 从数据库加载已知人脸
        conn = sqlite3.connect('access_control.db')
        cursor = conn.cursor()
        cursor.execute("SELECT id, name, face_encoding FROM users")
        rows = cursor.fetchall()
        conn.close()
        
        for row in rows:
            user_id, name, encoding_blob = row
            encoding = np.frombuffer(encoding_blob, dtype=np.float64)
            self.known_ids.append(user_id)
            self.known_names.append(name)
            self.known_faces.append(encoding)
            
    def add_face(self, user_id, name, face_encoding):
        # 添加新面孔到系统
        self.known_ids.append(user_id)
        self.known_names.append(name)
        self.known_faces.append(face_encoding)
        
    def recognize_face(self, frame):
        # 转换为RGB颜色空间
        rgb_frame = frame[:, :, ::-1]
        
        # 查找人脸位置
        face_locations = face_recognition.face_locations(rgb_frame)
        face_encodings = face_recognition.face_encodings(rgb_frame, face_locations)
        
        recognized_name = "Unknown"
        recognized_id = -1
        
        for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):
            # 尝试匹配已知人脸
            matches = face_recognition.compare_faces(self.known_faces, face_encoding)
            face_distances = face_recognition.face_distance(self.known_faces, face_encoding)
            
            if len(face_distances) > 0:
                best_match_index = np.argmin(face_distances)
                if matches[best_match_index]:
                    recognized_name = self.known_names[best_match_index]
                    recognized_id = self.known_ids[best_match_index]
        
        return recognized_id, recognized_name
        
    def start_recognition(self):
        # 启动人脸识别线程
        threading.Thread(target=self._recognition_loop, daemon=True).start()
        
    def _recognition_loop(self):
        # 人脸识别主循环
        self.camera = cv2.VideoCapture(0)
        
        while True:
            try:
                ret, frame = self.camera.read()
                if not ret:
                    continue
                    
                # 每2秒进行一次人脸识别
                current_time = time.time()
                if hasattr(self, 'last_recognition_time'):
                    if current_time - self.last_recognition_time < 2:
                        continue
                self.last_recognition_time = current_time
                
                # 进行人脸识别
                user_id, user_name = self.recognize_face(frame)
                
                # 记录访问日志
                timestamp = time.strftime('%Y-%m-%d %H:%M:%S')
                
                if user_id != -1:
                    # 识别成功，允许访问
                    print(f"识别成功: {user_name}")
                    self.log_access(user_id, user_name, "成功")
                    
                    # 发送开门指令到Arduino
                    if ser and ser.is_open:
                        ser.write(b"UNLOCK\n")
                else:
                    # 识别失败
                    print("未识别的人脸")
                    self.log_access(-1, "Unknown", "失败")
                    
            except Exception as e:
                print(f"人脸识别错误: {e}")
                time.sleep(1)
                
    def log_access(self, user_id, user_name, result):
        # 记录访问日志
        timestamp = time.strftime('%Y-%m-%d %H:%M:%S')
        conn = sqlite3.connect('access_control.db')
        cursor = conn.cursor()
        cursor.execute(
            "INSERT INTO access_logs (user_id, user_name, access_time, result) VALUES (?, ?, ?, ?)",
            (user_id, user_name, timestamp, result)
        )
        conn.commit()
        conn.close()
        
# 创建人脸识别系统实例
face_system = FaceRecognitionSystem()
face_system.start_recognition()

# Web路由
@app.route('/')
def index():
    return render_template('index.html')

@app.route('/admin')
def admin_dashboard():
    # 获取最近的访问日志
    conn = sqlite3.connect('access_control.db')
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM access_logs ORDER BY access_time DESC LIMIT 50")
    logs = cursor.fetchall()
    
    # 获取用户列表
    cursor.execute("SELECT * FROM users")
    users = cursor.fetchall()
    
    # 获取访客列表
    cursor.execute("SELECT * FROM visitors")
    visitors = cursor.fetchall()
    
    conn.close()
    
    return render_template('admin.html', logs=logs, users=users, visitors=visitors)

@app.route('/api/unlock', methods=['POST'])
def unlock_door():
    # 远程开门
    if ser and ser.is_open:
        ser.write(b"UNLOCK\n")
        return jsonify({'success': True, 'message': '门已打开'})
    else:
        return jsonify({'success': False, 'message': '无法连接到门禁控制器'})

@app.route('/api/status')
def get_status():
    # 获取门禁状态
    status = "未知"
    if ser and ser.is_open:
        ser.write(b"STATUS\n")
        time.sleep(0.5)
        if ser.in_waiting > 0:
            response = ser.readline().decode('utf-8').strip()
            status = response
    
    return jsonify({'status': status})

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')